home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DJGPP / DJLSR111.ZIP / libsrc / c / io / popen.c < prev    next >
C/C++ Source or Header  |  1993-08-29  |  7KB  |  260 lines

  1. /*
  2.    This is popen() and pclose() for MSDOS.  They were developed using
  3.    Microsoft C, but should port easily to DOS C any compiler.
  4.    
  5.    Original author: pacetti@fl-ngnet.army.mil
  6.  
  7.    These routines are hacks, that is they SIMULATE thier UNIX
  8.    counterparts.  Since MSDOS and won't allow concurrent process spawning,
  9.    you can't really pipe.  I came up with this nearly stupid way around
  10.    piping because I wanted to have some portability between UNIX and MSDOS.
  11.    I'm probably not the first person to have this idea or implement it, but
  12.    I think I'm the first to give it away for free (no points?!).
  13.  
  14.    The functions simulate popen() and pclose() by redirecting stdin or
  15.    stdout, then spawning a child processes via system().
  16.  
  17.    If you popen() for read, the stdout is redirected to a temporary
  18.    file, and the child is spawned.  The stdout is reopened via dup2(), the
  19.    temporary file is opened for read and a file pointer to it is returned.
  20.  
  21.    If you popen() for write, a temporary file is opened for write, and
  22.    a file pointer to it is returned.  When you pclose(), the stdin is
  23.    redirected to the temporary file and the child is spawned.
  24.  
  25.    In both cases, pclose() closes and unlinks the temporary file.
  26.  
  27.    A static linked list of C structures is built to store necessary
  28.    info for all popen()ed files so you can popen() more than one file at
  29.    a time.
  30.  
  31.    The popen() function will return NULL on an error, or a valid FILE
  32.    *pointer on a successful open.  The pclose() function will return
  33.    negative one (-1) on an error or zero (0) on a successful close.
  34.  
  35.    The function prototypes are:
  36.  
  37.    FILE *popen(command, mode)
  38.         char *command, char *mode;
  39.  
  40.    int pclose(pp)
  41.        FILE *pp;
  42.  
  43.    Where command is a character string equivilant to a MSDOS command
  44.    line, mode is "r" for read or "w" for write, and pp is a pointer to a
  45.    file opened through popen().
  46.  
  47.    A main() function has been included for testing purposes, to compile
  48.    it define the preprocessor token TEST at compile time.
  49.  */
  50.  
  51. #include <io.h>
  52. #include <errno.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56.  
  57. /* hold file pointer, descriptor, command, mode, temporary file name */
  58. struct pipe_list
  59.   {
  60.     FILE *fp;
  61.     int fd;
  62.     char *command, mode[2], temp_name[13];
  63.     struct pipe_list *next;
  64.   };
  65.  
  66. /* static, global list pointer */
  67. static struct pipe_list *pl = NULL;
  68.  
  69. FILE *
  70. popen (cm, md)
  71.      const char *cm, *md;             /* program name, pipe mode */
  72. {
  73.   struct pipe_list *l1, *l2;
  74.   static char *tn = NULL;       /* temporary file basename */
  75.  
  76.   if (!tn)
  77.     if ((tn = mktemp ("pXXXXXX")) == NULL)
  78.       return (NULL);
  79.  
  80.   /* make new node */
  81.   if ((l1 = (struct pipe_list *) malloc (sizeof (struct pipe_list))) == NULL)
  82.       return (NULL);
  83.  
  84.   /* zero out elemets to we'll get here */
  85.   l1->fd = 0;
  86.   l1->fp = NULL;
  87.   l1->next = NULL;
  88.  
  89.   /* if empty list - just grab new node */
  90.   if (!pl)
  91.     pl = l1;
  92.   else
  93.     {
  94.       /* otherwise, find last node in list */
  95.       ++(l1->fd);
  96.       l2 = pl;
  97.       while (l2->next)
  98.         {
  99.           ++(l1->fd);
  100.           l2 = l2->next;
  101.         };
  102.       /* add new node to list */
  103.       l2->next = l1;
  104.     }
  105.  
  106.   /* stick in elements we know already */
  107.   strcpy (l1->mode, md);
  108.   sprintf (l1->temp_name, "%s.%d", tn, l1->fd);
  109.  
  110.   /* if can save the program name, build temp file */
  111.   if (l1->command = strdup (cm))
  112.     {
  113.       /* if caller wants to read */
  114.       if (!strcmp (l1->mode, "r"))
  115.         {
  116.           /* dup stdout */
  117.           if ((l1->fd = dup (fileno (stdout))) == EOF)
  118.             l1->fp = NULL;
  119.           else if (!(l1->fp = freopen (l1->temp_name, "wb", stdout)))
  120.             l1->fp = NULL;
  121.           else
  122.             /* exec cmd */
  123.           if (system (cm) == EOF)
  124.             l1->fp = NULL;
  125.           /* reopen real stdout */
  126.           if (dup2 (l1->fd, fileno (stdout)) == EOF)
  127.             l1->fp = NULL;
  128.           else
  129.             /* open file for reader */
  130.             l1->fp = fopen (l1->temp_name, "r");
  131.         }
  132.       else
  133.         /* if caller wants to write */
  134.       if (!strcmp (l1->mode, "w"))
  135.         /* open temp file */
  136.         l1->fp = fopen (l1->temp_name, "w");
  137.       else
  138.         /* unknown mode */
  139.         l1->fp = NULL;
  140.     }
  141.   return (l1->fp);              /* return == NULL ? ERROR : OK */
  142. }
  143.  
  144. int
  145. pclose (pp)
  146.      FILE *pp;
  147. {
  148.   struct pipe_list *l1, *l2;    /* list pointers */
  149.   int retval;                   /* function return value */
  150.  
  151.   /* if pointer is first node */
  152.   if (pl->fp == pp)
  153.     {
  154.       /* save node and take it out the list */
  155.       l1 = pl;
  156.       pl = l1->next;
  157.     }
  158.   else
  159.     /* if more than one node in list */
  160.   if (pl->next)
  161.     {
  162.       /* find right node */
  163.       for (l2 = pl, l1 = pl->next; l1; l2 = l1, l1 = l2->next)
  164.         if (l1->fp == pp)
  165.           break;
  166.  
  167.       /* take node out of list */
  168.       l2->next = l1->next;
  169.     }
  170.   else
  171.     return (-1);
  172.  
  173.   /* if FILE not in list - return error */
  174.   if (l1->fp == pp)
  175.     {
  176.       /* close the (hopefully) popen()ed file */
  177.       fclose (l1->fp);
  178.  
  179.       /* if pipe was opened to write */
  180.       if (!strcmp (l1->mode, "w"))
  181.         {
  182.           /* dup stdin */
  183.           if ((l1->fd = dup (fileno (stdin))) == EOF)
  184.             retval = -1;
  185.           else
  186.             /* open temp stdin */
  187.           if (!(l1->fp = freopen (l1->temp_name, "rb", stdin)))
  188.             retval = -1;
  189.           else
  190.             /* exec cmd */
  191.           if (system (l1->command) == EOF)
  192.             retval = -1;
  193.           else
  194.             /* reopen stdin */
  195.           if (dup2 (l1->fd, fileno (stdin)) == EOF)
  196.             retval = -1;
  197.         }
  198.       else
  199.         /* if pipe was opened to read */
  200.       if (!strcmp (l1->mode, "r"))
  201.         retval = 0;
  202.       else
  203.         /* invalid mode */
  204.         retval = -1;
  205.     }
  206.   unlink (l1->temp_name);       /* remove temporary file */
  207.   free (l1->command);           /* dealloc memory */
  208.   free (l1);                    /* dealloc memory */
  209.   l1 = NULL;                    /* make pointer bogus */
  210.  
  211.   return (retval);              /* retval==0 ? OK : ERROR */
  212. }
  213.  
  214. #ifdef TEST
  215. /* little test routine - for non-believers (like me).
  216.    Note that it does no diagnostics!  It takes for granted
  217.    that it will work! #define TEST to try it */
  218. main ()
  219. {
  220.   FILE *pp1, *pp2, *pp3, *pp4;
  221.  
  222.   pp1 = popen ("find \"find\"", "w");
  223.   Write2pipe (pp1);
  224.  
  225.   pp2 = popen ("dir /w", "r");
  226.   Readfrompipe (pp2);
  227.  
  228.   pp3 = popen ("more", "w");
  229.   Write2pipe (pp3);
  230.  
  231.   pp4 = popen ("dir", "r");
  232.   Readfrompipe (pp4);
  233.  
  234.   pclose (pp1);
  235.   pclose (pp3);
  236.   pclose (pp4);
  237.   pclose (pp2);
  238. }
  239.  
  240. Write2pipe (pipe)
  241.      FILE *pipe;
  242. {
  243.   char buf[81];
  244.   FILE *pp;
  245.  
  246.   pp = fopen ("popen.c", "r");
  247.  
  248.   while (fgets (buf, 80, pp) != NULL)
  249.     fprintf (pipe, "%s", buf);
  250. }
  251. Readfrompipe (pipe)
  252.      FILE *pipe;
  253. {
  254.   char buf[81];
  255.  
  256.   while (fgets (buf, 80, pipe) != NULL)
  257.     printf ("%s", buf);
  258. }
  259. #endif
  260.